﻿using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Security.Principal;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;

namespace DotNetStar.TheKing.Web
{
    using Domain;
    using DotNetStar.TheKing.Services;
    using Microsoft.AspNetCore.Authentication;
    using System.Security.Claims;

    public static class ClaimIdentityExtension
    {
        public static Task SignInAsync(this HttpContext context, User user)
        {
            var claims = new List<Claim>();

            foreach (var item in user.GetType().GetProperties())
            {
                var type = item.Name;
                var value = item.GetValue(user)?.ToString();
                
                switch (type)
                {
                    case nameof(User.Id):
                        claims.Add(new Claim(ClaimTypes.NameIdentifier, value));
                        break;
                    case nameof(User.UserName):
                        claims.Add(new Claim(ClaimTypes.Name, value));
                        break;

                    case nameof(User.Role):
                        claims.Add(new Claim(ClaimTypes.Role, value));
                        break;
                    default:
                        if (!value.IsNullOrWhiteSpace())
                        {
                            claims.Add(new Claim(type, value));
                        }
                        break;
                }
                

            }


            var userIdentity = new ClaimsIdentity("DNS");
            
            userIdentity.AddClaims(claims);
            var userPriciple = new ClaimsPrincipal(userIdentity);

            return context.SignInAsync(userPriciple);
        }

        public static long UserId(this IIdentity identity)
        {
            if (!identity.IsAuthenticated)
            {
                return 0;
            }

            return identity.GetClaimValue<long>(ClaimTypes.NameIdentifier); 
        }

        public static string UserName(this IIdentity identity)
            => identity.GetClaimValue<string>(ClaimTypes.Name);
        
        public static string UserAvatar(this IIdentity identity)
            => identity.GetClaimValue<string>(nameof(User.AvatarUrl));

        public static void UpdateClaim(this IIdentity identity,string type, string value)
        {
            var claimIdentity = (identity as ClaimsIdentity);
            claimIdentity.TryRemoveClaim(identity.GetClaim(type));
            claimIdentity.AddClaim(new Claim(type, value));
        }

        public static void UpdateUserName(this IIdentity identity, string value)
            => identity.UpdateClaim(ClaimTypes.Name, value);
   
        public static Task UpdateAsync(this HttpContext context,User user)
        {
            foreach (var item in user.GetType().GetProperties())
            {

                var type = item.Name;
                var value = item.GetValue(user)?.ToString();

                if (type == nameof(User.Id))
                {
                    continue;
                }

                switch (type)
                {

                    case nameof(User.UserName):
                        context.User.Identity.UpdateClaim(ClaimTypes.Name, value);
                        break;

                    case nameof(User.Role):
                        context.User.Identity.UpdateClaim(ClaimTypes.Role, value);
                        break;
                    default:
                        if (!value.IsNullOrWhiteSpace())
                        {
                            context.User.Identity.UpdateClaim(type, value);
                        }
                        break;
                }

            }
            return Task.CompletedTask;
        }

        /// <summary>
        /// 获取指定声明类型的声明对象。
        /// </summary>
        /// <param name="identity"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static Claim GetClaim(this IIdentity identity, string type)
            => (identity as ClaimsIdentity)?.FindFirst(type);

        /// <summary>
        /// 获取指定声明类型的值。若声明类型没找到，则返回泛型类型的默认值。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="identity"></param>
        /// <param name="type">声明类型。</param>
        /// <returns></returns>
        public static T GetClaimValue<T>(this IIdentity identity, string type)
        {
            var claim = identity.GetClaim(type);
            if (claim == null)
            {
                return default(T);
            }
           return claim.Value.To(default(T));
        }

        public static string GetClaimValue(this IIdentity identity, string type) =>identity.GetClaimValue<string>(type);

        /// <summary>
        /// 刷新，即从数据库里获取
        /// </summary>
        /// <param name="context"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        public static async Task RefreshAsync(this HttpContext context,long userId)
        {
            var user = await context.RequestServices.GetService<UserService>().GetByIdAsync(userId);
            if (user != null)
            {
               await  UpdateAsync(context, user);
            }
        }
    }
}
